Kokaのoperation keywords
↑正式な総称が不明なので適当にタイトルを付けているmrsekut.icon
ctl
val
return
fun
ctl
最も愚直にhandlerの内容を書く方法
with ctl op(<args>){ <body> }という構文
例
code:koka(js)
fun raise-const() : int
with ctl raise(msg) 42
...
raiseというeffectに対するhandlerを定義している
fun
以下2つは同じ意味
code:koka(js)
with fun op(<args>){ <body> }
code:koka(js)
with ctl op(<args>){ val f = fn(){ <body> }; resume( f() ) }
ただし、内部的にはただの糖衣構文ではなく、前者の方が最適化しやすいらしい
funと書いた時点で、resumeすることが含意されている
そのため、funの方にはわざわざresumeというキーワードが登場しない
例
code:koka(js)
fun ask-const2() : int
with fun ask() 21
add-twice()
こんなふうにも読めそうmrsekut.icon
handlerではない実際の処理側で、askを使っている箇所を、全てここで定義したものに置き換える
つまり、injectionしてる
val
以下2つは同じ意味
code:koka(js)
with val v = <expr>
code:koka(js)
val x = <expr>
with ctl v(){ resume(x) }
例
code:koka(js)
// 値としてeffectを用意
effect val width : int
// widthを内部で使っている関数。widthは引数で受け取っているわけではない
fun pretty-internal( line : string ) : width string
line.truncate(width)
// 上記の関数を呼び出すhandler。width=40と設定して実行している
fun pretty-thin(d : doc) : string
with val width = 40
pretty(d)
値をeffectで表現することで、外側から値のinjectionができる
安全なglobal変数とも見れる
引数でバケツリレーする必要もなく、globalなmutable変数とも違う
型で明示されるので設定し忘れがない
pretty-thin以上の呼び出し元からはwidthを変更することはできない
スコープが限られている
そのglobal変数は、どこからでも変更可能、にはなってなくて安心安全
return
特定のhandlerを通過せずに、通常終了したときの最終返り値を変換するだけ
例
raiseをmaybeに変換するhandler
code:koka(js)
fun raise-maybe( action : () -> <raise|e> a ) : e maybe<a>
with handler
return(x) Just(x) // normal return: wrap in Just
ctl raise(msg) Nothing // exception: return Nothing directly
action()
fun div42()
(raise-maybe{ safe-divide(1,0) }).default(42)
raw ctl